package com.nowcoder.community.service;

import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.baomidou.mybatisplus.core.conditions.update.UpdateWrapper;
import com.nowcoder.community.config.CommunityConfig;
import com.nowcoder.community.controller.exception.PageNotFoundException;
import com.nowcoder.community.dao.CommonRedisDao;
import com.nowcoder.community.entity.*;
import com.nowcoder.community.mapper.LoginTicketMapper;
import com.nowcoder.community.mapper.MessageMapper;
import com.nowcoder.community.mapper.UserMapper;
import com.nowcoder.community.util.Constants;
import com.nowcoder.community.util.CommunityUtils;
import com.nowcoder.community.util.HostHolder;
import com.nowcoder.community.util.MailClient;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.web.servlet.ModelAndView;
import org.thymeleaf.TemplateEngine;
import org.thymeleaf.context.Context;

import javax.servlet.http.Cookie;
import java.util.*;

import static com.nowcoder.community.util.Constants.*;

@Service
@Slf4j
public class UserService {

    public static final int MAX_CACHE_EXPIRE_MINUTE = 30;

    @Autowired
    UserMapper userMapper;

    @Autowired
    LoginTicketMapper loginTicketMapper;

    @Autowired
    MessageMapper messageMapper;

    @Autowired
    TemplateEngine templateEngine;

    @Autowired
    CommunityConfig appConfig;

    @Autowired
    MailClient mailClient;

    @Autowired
    HostHolder hostHolder;

    @Autowired
    CommonRedisDao commonRedisDao;

    public User findUserById(int id) {
        User user = commonRedisDao.getUserById(id);
        if (user == null) {
            log.debug("User<{}>缓存失效! ", id);
            user = userMapper.selectById(id);
            cacheUser(user);
        } else {
            log.debug("User<{}>缓存命中! {}", user.getId(), user);
        }
        return user;
    }

    public ModelAndView login(User user, boolean isRememberMe) {
        ModelAndView ret = new ModelAndView("site/login");
        User dUser = userMapper.selectByName(user.getUsername());
        if (dUser == null) {
            ret.addObject("usernameMsg", "该用户不存在!");
            return ret;
        }

        if (!Objects.equals(dUser.getPassword(), CommunityUtils.md5(user.getPassword() + dUser.getSalt()))) {
            ret.addObject("passwordMsg", "该密码错误!");
            return ret;
        }

        int expiredMinute = isRememberMe ? DEFAULT_REMEMBER_ME_EXPIRED_MINUTE : DEFAULT_EXPIRED_MINUTE;
        LoginTicket ticket = CommunityUtils.createLoginTicket(dUser, expiredMinute);
        loginTicketMapper.insert(ticket);
        Cookie cookie = new Cookie("ticket", ticket.getTicket());
        cookie.setPath("/");
        cookie.setMaxAge(expiredMinute * 60);
        CommunityUtils.addCookie(ret, cookie);
        ret.setViewName("redirect:/index");
        return ret;
    }

    private void cacheUser(User user) {
        if (user != null) {
            commonRedisDao.setUser(user.getId(), user, MAX_CACHE_EXPIRE_MINUTE * 60);
        }
    }

    private void unCacheUser(int id) {
        commonRedisDao.delUserById(id);
    }

    private void cacheLoginTicket(LoginTicket ticket) {
        if (ticket != null) {
            commonRedisDao.setLoginTicket(ticket.getTicket(), ticket, MAX_CACHE_EXPIRE_MINUTE * 60);
        }
    }

    private void unCacheLoginTicket(String ticket) {
        commonRedisDao.delLoginTicket(ticket);
    }

    public ModelAndView logout(String ticket) {
        if (ticket != null && ticket.length() > 0) {
            loginTicketMapper.updateStatus(ticket, 1);
            unCacheLoginTicket(ticket);
        }
        return new ModelAndView("redirect:index");
    }

    public ModelAndView register(User user) {
        ModelAndView ret = new ModelAndView();
        boolean errFlag = false;
        long count = userMapper.selectCount(new QueryWrapper<User>() {{eq("username", user.getUsername());}});
        if (count > 0){
            ret.addObject("usernameMsg", "用户已存在!");
            errFlag = true;
        }
        count = userMapper.selectCount(new QueryWrapper<User>() {{eq("email", user.getEmail());}});
        if (count > 0){
            ret.addObject("emailMsg", "邮箱已存在!");
            errFlag = true;
        }
        if (errFlag) {
            ret.setViewName("site/register");
            return ret;
        }
        user.setSalt(CommunityUtils.generateSalt());
        user.setPassword(CommunityUtils.encodePassword(user.getPassword(), user.getSalt()));
        user.setType(0);
        user.setStatus(0);
        user.setActivationCode(CommunityUtils.generateUUID());
        user.setHeaderUrl(String.format("http://images.nowcoder.com/head/%dt.png", new Random().nextInt(1000)));
        userMapper.insert(user);

        Context context = new Context();
        context.setVariable("username", user.getUsername());
        context.setVariable("url",  appConfig.getPathDomain() + "/activation/" + user.getId() + "/" + user.getActivationCode());
        String content = templateEngine.process("mail/activation", context);
        mailClient.sendMail(user.getEmail(), "牛子-账号激活", content);

        ret.setViewName("site/operate-result");
        ret.addObject("msg", String.format("注册成功, 我们已经向(%s)发送了一封激活邮件,请到邮箱查看,如没有收到请检查垃圾箱.", user.getEmail()));
        ret.addObject("targetUrl", "/index");
        return ret;
    }

    public ModelAndView active(User user) {
        ModelAndView ret = new ModelAndView("site/operate-result");
        User dUser = userMapper.selectById(user.getId());
        if (dUser == null || dUser.getStatus() == 1 || !Objects.equals(user.getActivationCode(), dUser.getActivationCode())) {
            log.warn("用户激活失败: " + user);
            ret.addObject("msg", "激活失败, 请联系管理员.");
            ret.addObject("targetUrl", "/index");
            return ret;
        }
        userMapper.update(null, new UpdateWrapper<User>() {
            {
                set("status", 1);
                eq("id", dUser.getId());
            }
        });
        ret.addObject("msg", "账号激活成功!");
        ret.addObject("targetUrl", "/login");
        unCacheUser(user.getId());
        return ret;
    }

    public LoginTicket findLoginTicket(String ticket) {
        LoginTicket t = commonRedisDao.getLoginTicket(ticket);
        if (t == null) {
            log.debug("loginTicket<{}>缓存失效! ", ticket);
            t = loginTicketMapper.selectByTicket(ticket);
            cacheLoginTicket(t);
        } else {
            log.debug("loginTicket<{}>缓存命中! {}", ticket, t);
        }

        return t;
    }

    public void updatePassword(int userId, String password) {
        userMapper.updatePassword(userId, password);
        unCacheUser(userId);
    }

    public ModelAndView letterDetail(String conversationId, Page page) throws PageNotFoundException {
        ModelAndView ret = new ModelAndView("/site/letter-detail");
        User loginUser = hostHolder.getUser();

        UserConversation conversation = messageMapper.selectConversationById(conversationId);
        if (conversation == null) {
            throw new PageNotFoundException("没有该会话信息");
        }

        // set target user;
        int targetUserId = conversation.getMessage().getFromId();
        if (targetUserId == loginUser.getId()) {
            targetUserId = conversation.getMessage().getToId();
        }
        conversation.setTargetUser(userMapper.selectById(targetUserId));

        page.setRows(messageMapper.countLettersById(conversationId));
        List<Integer> readMsgIds = new ArrayList<>();
        if (page.getRows() > 0) {
            conversation.setLetters(messageMapper.selectLetters(conversationId, page.getOffset(), page.getLimit()));
            for (Message letter : conversation.getLetters()) {
                if (letter.getStatus() == MESSAGE_STATUS_UNREAD && Objects.equals(letter.getToId(), loginUser.getId())) {
                    readMsgIds.add(letter.getId());
                }
            }
            if (!readMsgIds.isEmpty()) {
                messageMapper.updateStatusById(readMsgIds, Constants.MESSAGE_STATUS_READ);
            }
        } else {
            conversation.setLetters(new ArrayList<>());
        }

        ret.addObject("page", page);
        ret.addObject("conversation", conversation);
        return ret;
    }

    public void updateHeaderUrl(int id, String headerUrl) {
        userMapper.updateHeaderUrl(id, headerUrl);
        unCacheUser(id);
    }
}
